package com.mall.user.services;

import com.alibaba.fastjson.JSON;
import com.mall.commons.tool.exception.ValidateException;
import com.mall.user.IRegisterService;
import com.mall.user.constants.SysRetCodeConstants;
import com.mall.user.dal.entitys.Member;
import com.mall.user.dal.entitys.UserVerify;
import com.mall.user.dal.persistence.MemberMapper;
import com.mall.user.dal.persistence.UserVerifyMapper;
import com.mall.user.dto.UserRegisterRequest;
import com.mall.user.dto.UserRegisterResponse;
import com.mall.user.dto.UserVerifyRequest;
import com.mall.user.dto.UserVerifyResponse;
import com.mall.user.utils.ExceptionProcessorUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * @description:
 * @autyor:caicaicai
 */
@Slf4j//用于打印日志
@Component//注册组件
@Service//暴露微服务，注意不要导包错误（导成注册组件的包）
public class RegisterServiceImpl implements IRegisterService {

    @Autowired//从容器中取出组件
    MemberMapper memberMapper;

    @Autowired
    UserVerifyMapper userVerifyMapper;

    @Autowired//?为什么报红仍能执行？该组件在哪里注册的？
    JavaMailSender javaMailSender;

    @Transactional//前后添加两表涉及到事务
    @Override
    public UserRegisterResponse register(UserRegisterRequest registerRequest) {
        UserRegisterResponse registerResponse= new UserRegisterResponse();

        try {
            //判空验证
            registerRequest.requestCheck();
        } catch (ValidateException ve) {//用户名或密码不能为空
            ExceptionProcessorUtils.wrapperHandlerException(registerResponse, ve);
            registerResponse.setCode(SysRetCodeConstants.REQUISITE_PARAMETER_NOT_EXIST.getCode());
            registerResponse.setMsg(SysRetCodeConstants.REQUISITE_PARAMETER_NOT_EXIST.getMessage());
            return registerResponse;
        }

        try {
            //验证用户名是否重复
            volidUserNameRepeat(registerRequest);
        }catch (ValidateException ve){//用户名已存在
          ExceptionProcessorUtils.wrapperHandlerException(registerResponse, ve);
          registerResponse.setCode(SysRetCodeConstants.USERNAME_ALREADY_EXISTS.getCode());
          registerResponse.setMsg(SysRetCodeConstants.USERNAME_ALREADY_EXISTS.getMessage());
          return registerResponse;
        }
        log.info("注册service 之 验证用户名是否重复已完成：用户名不存在即可用");

        try {
            //验证用户名是否重复
            volidEmailRepeat(registerRequest);
        }catch (ValidateException ve){//邮箱已存在
            ExceptionProcessorUtils.wrapperHandlerException(registerResponse, ve);
            registerResponse.setCode(SysRetCodeConstants.REMAIL_ALREADY_EXISTS.getCode());
            registerResponse.setMsg(SysRetCodeConstants.REMAIL_ALREADY_EXISTS.getMessage());
            return registerResponse;
        }
        log.info("注册service 之 验证邮箱是否重复已完成：邮箱不存在即可用");

        //1.向用户表中插入一条记录
        Member member = new Member();
        //从前端来的数据：username、userpwd、email
        member.setUsername(registerRequest.getUserName());
        member.setEmail(registerRequest.getEmail());
        //password 要加密处理
        //注册中加密、登录验证加密的方法必须一样
        String userPwd = DigestUtils.md5DigestAsHex(registerRequest.getUserPwd().getBytes());
        member.setPassword(userPwd);

        member.setCreated(new Date());
        member.setUpdated(new Date());
        member.setIsVerified("N");//是否认证：N
        member.setState(1);//本次开发中不使用该属性，初始化为1

        int effectRows = memberMapper.insert(member);
        if(effectRows != 1){
            //service层 --> controller层：DTO(code, msg)
            log.error("注册service 之 添加member表失败");
            registerResponse.setCode(SysRetCodeConstants.USER_REGISTER_FAILED.getCode());
            registerResponse.setMsg(SysRetCodeConstants.USER_REGISTER_FAILED.getMessage());
            return registerResponse;
        }
        log.info("注册service 之 添加member表成功");

        //2.向用户验证表中插入一条记录
        UserVerify userVerify = new UserVerify();
        userVerify.setUsername(member.getUsername());
        //uuid生成算法：自定义，保证唯一可标识唯一一条用户验证记录即可，这里如下
        // key(拼接 + 随机生成) --> uuid（md5码加密，保证唯一）
        //uuid：必须唯一 --> 通过它可找到发送邮件的这条激活记录id --> userName
        String key = member.getUsername() + member.getPassword() + UUID.randomUUID().toString();
        String uuid = DigestUtils.md5DigestAsHex(key.getBytes());
        userVerify.setUuid(uuid);

        userVerify.setRegisterDate(new Date());
        userVerify.setIsExpire("N");
        userVerify.setIsVerify("N");

        int rows = userVerifyMapper.insert(userVerify);
        if(rows != 1){
            log.error("注册service 之 添加userVerify表失败");
            registerResponse.setCode(SysRetCodeConstants.USER_REGISTER_VERIFY_FAILED.getCode());
            registerResponse.setMsg(SysRetCodeConstants.USER_REGISTER_VERIFY_FAILED.getMessage());
            return registerResponse;
        }
        log.error("注册service 之 添加userVerify表成功");

        //3.发送用户激活邮件
        //发送用户激活邮件 激活邮件应该是一个链接 有一个接口去处理我们的用户激活 优化：线程 --> 消息中间件MQ
        new Thread() {
            @Override
            public void run() {
                sendEmail(uuid, registerRequest);
            }
        }.start();

        //响应，操作成功
        //打印日志（工作中必须打印日志，千万不要通过system.out、print等打印到控制台）
        //打印效果：用户注册成功，注册参数request:registerRequest, xxx
        log.info("用户注册成功，注册参数request:{}", JSON.toJSONString(registerRequest));
        registerResponse.setCode(SysRetCodeConstants.SUCCESS.getCode());
        registerResponse.setMsg(SysRetCodeConstants.SUCCESS.getMessage());
        return registerResponse;
    }

    @Transactional//事务
    @Override
    public UserVerifyResponse verify(UserVerifyRequest verifyRequest) {
        UserVerifyResponse verifyResponse = new UserVerifyResponse();

        //1.修改userVerify表的is_verify为Y
        UserVerify userVerify = new UserVerify();
        userVerify.setIsVerify("Y");
        Example example = new Example(UserVerify.class);
        example.createCriteria().andEqualTo("uuid", verifyRequest.getUuid())
                .andEqualTo("username", verifyRequest.getUserName());
        //根据后example(uuid username)修改前userVerify(isVerify)
        int effectedRows = userVerifyMapper.updateByExampleSelective(userVerify, example);
        if(effectedRows != 1){
            log.error("用户激活service 之 修改userVerify失败");
            verifyResponse.setCode(SysRetCodeConstants.USER_ISVERFIED_ERROR.getCode());
            verifyResponse.setMsg(SysRetCodeConstants.USER_ISVERFIED_ERROR.getMessage());
            return verifyResponse;
        }
        log.info("用户激活service 之 修改userVerify表成功");

        //2.修改member表的isVerified为Y
        Member member = new Member();
        member.setUsername(verifyRequest.getUserName());
        member.setIsVerified("Y");
        member.setUpdated(new Date());
        //member.setUsername(verifyRequest.getUserName());
        Example memberExample = new Example(Member.class);
        memberExample.createCriteria().andEqualTo("username", verifyRequest.getUserName());
        //根据后example(username)修改前member(isverified)
        int memberEffectedRows = memberMapper.updateByExampleSelective(member, memberExample);
        if(memberEffectedRows != 1){
            log.error("用户激活service 之 修改member表失败");
            verifyResponse.setCode(SysRetCodeConstants.USER_ISVERFIED_ERROR.getCode());
            verifyResponse.setMsg(SysRetCodeConstants.USER_ISVERFIED_ERROR.getMessage());
            return verifyResponse;
        }
        log.error("用户激活service 之 修改member表成功");

        verifyResponse.setCode(SysRetCodeConstants.SUCCESS.getCode());
        verifyResponse.setMsg(SysRetCodeConstants.SUCCESS.getMessage());
        return verifyResponse;
    }

    /**
     * 发送用户激活邮件
     * @param uuid
     * @param registerRequest
     */
    private void sendEmail(String uuid, UserRegisterRequest registerRequest) {
        SimpleMailMessage message = new SimpleMailMessage();
        log.info("注册service 之 邮件发送开始");

        //todo 这些信息，建议写到配置文件中取
        message.setSubject("CSMALL用户激活");//邮件主题
        message.setFrom("caicaicai2019@qq.com");//邮件发送方
        message.setTo(registerRequest.getEmail());//邮件接收方（用户的注册邮箱）
        //message.setTo("caicaicai20212021@163.com");

        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("http://localhost:8080/user/verify?uuid=").append(uuid).append("&userName=").append(registerRequest.getUserName());
        //http://localhost:8080/user/verify?uuid=67e84ec931cbbbe3fec2f55168da2466&userName=1871871871
        message.setText(stringBuilder.toString());//邮件正文（处理用户激活的地址/请求url）

        javaMailSender.send(message);//发送邮件
        log.info("注册service 之 邮件已发送");
    }

    //验证用户名是否重复u
    //即查询用户表中是否存在此用户名
    private void volidUserNameRepeat(UserRegisterRequest registerRequest) {
        log.info("注册service 之 开始验证用户是否重复");
        //tk-mybatis提供的单表操作
        Example example = new Example(Member.class);
        example.createCriteria().andEqualTo("username", registerRequest.getUserName());
        List<Member> members = memberMapper.selectByExample(example);
        //select * from tb_member where userName = #{userName}

        if(!CollectionUtils.isEmpty(members)){
            //集合工具类.判空：查表结果集合非空，则抛出异常
            //异常工具类:向外层抛出异常（用户名已重复的枚举类型）
            log.error("注册service 之 用户名={}重复即已存在", registerRequest.getUserName());
           throw new ValidateException(SysRetCodeConstants.USERNAME_ALREADY_EXISTS.getCode(), SysRetCodeConstants.USERNAME_ALREADY_EXISTS.getMessage());
        }
    }

    private void volidEmailRepeat(UserRegisterRequest registerRequest) {
        log.info("注册service 之 开始验证用户是否重复");
        //tk-mybatis提供的单表操作
        Example example = new Example(Member.class);
        example.createCriteria().andEqualTo("email", registerRequest.getEmail());
        List<Member> members = memberMapper.selectByExample(example);
        //select * from tb_member where userName = #{userName}

        if(!CollectionUtils.isEmpty(members)){
            //集合工具类.判空：查表结果集合非空，则抛出异常
            //异常工具类:向外层抛出异常（用户名已重复的枚举类型）
            log.error("注册service 之 用户名={}重复即已存在", registerRequest.getUserName());
            throw new ValidateException(SysRetCodeConstants.REMAIL_ALREADY_EXISTS.getCode(), SysRetCodeConstants.USERNAME_ALREADY_EXISTS.getMessage());
        }
    }
}
